package net;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import beans.RunningTask;
import beans.RunningTaskBean;
import beans.Task;
import beans.UIAlgorithmDetail;
import dao.AlgorithmDao;
import dao.HistoryTaskDao;
import dao.ModelDao;
import dao.TaskDao;
import engine.BIEngine0_1.ParseTaskJson;
import engine.BIEngine0_1.TaskThread;
import utils.ExternalInterfaceParseUtil;
import utils.FtpuploadUtil;
import utils.Log4jInit;
import utils.Time2Str;
@Component
//@Scope("prototype")
@SuppressWarnings("Duplicates")
public class TaskOperator {

    private TaskDao taskDao;
    private AlgorithmDao algorithmDao;
    @Autowired
    private FtpuploadUtil ftpuploadUtil;
    //private JSONArray orders;
    public TaskOperator() {
        this.taskDao = new TaskDao();
        this.algorithmDao = new AlgorithmDao();
        //this.orders = new JSONArray();
    }

    public JSONObject startTask(String taskId, String batchTaskHash){
        Date date = new Date();
        JSONArray orders = new JSONArray();
        HistoryTaskDao historyDao = new HistoryTaskDao();
        List<Object> list = taskDao.getTaskById(taskId);

        JSONObject result = new JSONObject();
        JSONArray subTaskHashArray = new JSONArray();
        if (list.size() == 0) {
            result.put("message", "数据库无此任务");
            result.put("result", false);
            return result;
        } else {
            Task task = (Task) list.get(0);
            //从task bean中读取task json
            JSONObject taskJson = JSONObject.parseObject(task.getJson());
            boolean addResult = true;
            ParseTaskJson t = new ParseTaskJson();
            Set<String> algorithmIds = t.parseAlgorithmIds(taskJson);
            Map<String,List<String>> algorithmIdAndFtpUri = new HashMap<>();
            for(String one:algorithmIds)
            {
                //   algorithmIdAndFtpUri.put(one,ftpuploadUtil.uploadAlgorithmFileByAlgorithmId(one));
                JSONObject versionInfo = JSONObject.parseObject(algorithmDao.getVersionInfoById(one).toString());

//                 JSONArray ftpUri = (JSONArray) versionInfo.get("ftp_uri");
                String tmp = versionInfo.get("ftp_uri")==null?(String) versionInfo.get("ftp_uri"):versionInfo.get("ftp_uri").toString();
                JSONArray ftpUri;

                if(tmp==null || tmp.trim().equals("") || tmp.trim().equals("[]")){
                    ftpUri=new JSONArray();
                    Log4jInit.logger.info("tmp null::"+tmp);
                }else{
                    ftpUri =  versionInfo.getJSONArray("ftp_uri");//versionInfo.get("ftp_uri");
                    Log4jInit.logger.info("tmp::"+tmp);
                }
                String ftpVersion = (String) versionInfo.get("ftp_version");
                String version = (String) versionInfo.get("version");

                // 2019.3.26 如果ftp版本与算法版本一致，无需上传算法
                //          if((ftpUri!=null)&&(ftpVersion.equals(version))){
                if((ftpUri.size()!=0)&&(ftpVersion.equals(version))){
                    //JSONArray jsonArray = JSONArray.parseObject(ftpUri); //把String转换为json
                    algorithmIdAndFtpUri.put(one,JSONArray.parseArray(ftpUri.toString(), String.class));
                }else {
                    List<String> ftpUriList = ftpuploadUtil.uploadAlgorithmFileByAlgorithmId(one);
                    algorithmIdAndFtpUri.put(one,ftpUriList);
                    algorithmDao.updateVersionInfoById(one, JSON.toJSONString(ftpUriList), version);
                }

            }
            JSONArray blocksArray = taskJson.getJSONArray("blocks");
            //用于存放所有除开始节点、外部数据源节点、结束节点的blockId
            JSONArray blockIds = new JSONArray();
            //paramJsonObject存放运行参数配置，使用blockId作为键名，原json中键名为paramsConfig的json array作为键值
            JSONObject paramJsonObject = new JSONObject();
            for(int i=0;i<blocksArray.size();i++){
                //遍历每一个block
                JSONObject oneBlock = blocksArray.getJSONObject(i);
                //仅针对uiAlgorithm算法块，跳过外部数据源uiData、开始节点uiStart、结束节点uiEnd
                if(!(oneBlock.getString("blockId").contains("uiData")||oneBlock.getString("blockId").contains("uiStart")
                        ||oneBlock.getString("blockId").contains("uiEnd"))){
                    //处理没有设置默认参数值的情况
                    if(oneBlock.getJSONArray("paramsConfig").size()==0){
                        for(int index=0;index<taskJson.getIntValue("taskNumber");index++){
                            //可能存在的无算法执行参数的情况，这里前端无法传空的jsonarray过来，只能后台处理
                            oneBlock.getJSONArray("paramsConfig").add(new JSONArray());
                        }
                    }
                    //将有运行参数默认值的json array存入paramJsonObject中
                    paramJsonObject.put(oneBlock.getString("blockId"),oneBlock.getJSONArray("paramsConfig"));
                    blockIds.add(oneBlock.getString("blockId"));
                }
            }
            JSONArray inputJsonArray = taskJson.getJSONArray("inputs");
            JSONArray outputJsonArray = taskJson.getJSONArray("outputs");
            JSONArray settingsArray = new JSONArray();
            //处理input参数，inputJsonArray存放着每一个子任务的input、data参数
            for(int m = 0;m<inputJsonArray.size();m++){
                JSONObject oneFinal = new JSONObject();
                //获取每一个子任务的输入参数
                JSONArray oneTaskInputArray = inputJsonArray.getJSONObject(m).getJSONArray("input");
                JSONObject algorithmInput = new JSONObject();
                //遍历每一个子任务的输入参数数组
                for(int k=0;k<oneTaskInputArray.size();k++){
                    JSONObject oneAlgorithmInput = oneTaskInputArray.getJSONObject(k);
                    if(algorithmInput.containsKey(oneAlgorithmInput.getString("blockId"))){
                        algorithmInput.getJSONArray(oneAlgorithmInput.getString("blockId")).add(oneAlgorithmInput);
                    }else{
                        JSONArray temp = new JSONArray();
                        temp.add(oneAlgorithmInput);
                        algorithmInput.put(oneAlgorithmInput.getString("blockId"),temp);
                    }
                }
                oneFinal.put("inputs",algorithmInput);

                JSONObject oneTaskOutputObject = new JSONObject();
                oneTaskOutputObject.put("outputs",outputJsonArray.getJSONArray(m));
                oneFinal.put("outputs",oneTaskOutputObject);
                JSONObject algorithmParam = new JSONObject();
                for(int h=0;h<blockIds.size();h++){
                    String blockId = blockIds.getString(h);
                    algorithmParam.put(blockId,paramJsonObject.getJSONArray(blockId).getJSONArray(m));
                }
                oneFinal.put("params",algorithmParam);
                oneFinal.put("data",inputJsonArray.getJSONObject(m).getJSONArray("data"));
                settingsArray.add(oneFinal);
            }
            int size= settingsArray.size();
            t.setJSON(taskJson);
            List<String> subTaskHashList = new ArrayList<>();
            for(int index=0;index<size;index++){
                JSONObject jb =settingsArray.getJSONObject(index);
                String subTaskHash = UUID.randomUUID().toString().substring(0,20);
                subTaskHashList.add(subTaskHash);
                RunningTaskBean runningTaskBean = new RunningTaskBean(task.getTask_id() + "",
                        subTaskHash, task.getJson(), task.getName());
                runningTaskBean.setBatchTaskHash(batchTaskHash);
                runningTaskBean.setAlgorithmIdAndFtpUri(algorithmIdAndFtpUri);
                TaskThread taskA = new TaskThread(runningTaskBean);
                taskA.runningTaskBean.runnableObjects = t.toRunnerableObjectMap(taskA,index+1,
                        jb.getJSONArray("data"),
                        jb.getJSONObject("inputs"),
                        jb.getJSONObject("outputs"),
                        jb.getJSONObject("params"));
//                try {
//                	orders =returnOrderStr( t,orders);
//                	addResult=addResult&&historyDao.addHistoryByTask(task, subTaskHash,orders.toString(),taskHash);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                	}
                //    hTask.add(e)
                result=retResultMsg( addResult, taskA, subTaskHash, subTaskHashArray,result);
/****               if (addResult) {

 taskA.start();
 RunningTask.TASKMAP.setTask(taskA.runningTaskBean.getTaskHash(), taskA);
 subTaskHashArray.add(subTaskHash);
 result.put("message", "开始任务成功");
 result.put("result", true);

 } else {
 result.put("message", "添加历史任务时失败");
 result.put("result", false);
 }*******/
            }
            // 批量插入子任务
            addHistoryTask(task,subTaskHashList,batchTaskHash,historyDao);
            orders=returnOrderStr(t, orders);
            historyDao.addBatchTask(task, batchTaskHash,orders.toString(),date);
            result.put("batchTaskHash", batchTaskHash);
            result.put("orders",orders);
            return result;
        }
    }

    public JSONObject saveAndStartTask(Task task, String taskHash){
        List<Object> results = new TaskDao().addTask(task);
        if(results.size()>0){
            String taskId = results.get(0)+"";
            return this.startTask(taskId,taskHash);
        }else{
            JSONObject result = new JSONObject();
            result.put("result",false);
            result.put("message","新增任务时出错");
            return result;
        }
    }
    public List<TaskThread> produceTaskThread(Task oldTask, String batchTaskHash)
    {
        JSONArray orders = new JSONArray();
        List<TaskThread> taskThreadList = new ArrayList<>();
        List<Object> results = new TaskDao().addTask(oldTask);
        if(results.size()>0){
            String taskId = results.get(0)+"";
            HistoryTaskDao historyDao = new HistoryTaskDao();
            List<Object> list = taskDao.getTaskById(taskId);

            if (list.size() > 0) {
                Task task = (Task) list.get(0);
                //从task bean中读取task json
                JSONObject taskJson = JSONObject.parseObject(task.getJson());
                boolean addResult = true;
                ParseTaskJson t = new ParseTaskJson();
                JSONArray blocksArray = taskJson.getJSONArray("blocks");
                //用于存放所有除开始节点、外部数据源节点、结束节点的blockId
                JSONArray blockIds = new JSONArray();
                //paramJsonObject存放运行参数配置，使用blockId作为键名，原json中键名为paramsConfig的json array作为键值
                JSONObject paramJsonObject = new JSONObject();
                for(int i=0;i<blocksArray.size();i++){
                    //遍历每一个block
                    JSONObject oneBlock = blocksArray.getJSONObject(i);
                    //仅针对uiAlgorithm算法块，跳过外部数据源uiData、开始节点uiStart、结束节点uiEnd
                    if(!(oneBlock.getString("blockId").contains("uiData")||oneBlock.getString("blockId").contains("uiStart")
                            ||oneBlock.getString("blockId").contains("uiEnd"))){
                        //处理没有设置默认参数值的情况
                        if(oneBlock.getJSONArray("paramsConfig").size()==0){
                            for(int index=0;index<taskJson.getIntValue("taskNumber");index++){
                                //可能存在的无算法执行参数的情况，这里前端无法传空的jsonarray过来，只能后台处理
                                oneBlock.getJSONArray("paramsConfig").add(new JSONArray());
                            }
                        }
                        //将有运行参数默认值的json array存入paramJsonObject中
                        paramJsonObject.put(oneBlock.getString("blockId"),oneBlock.getJSONArray("paramsConfig"));
                        blockIds.add(oneBlock.getString("blockId"));
                    }
                }
                JSONArray inputJsonArray = taskJson.getJSONArray("inputs");
                JSONArray outputJsonArray = taskJson.getJSONArray("outputs");
                JSONArray dataJsonArray = taskJson.getJSONArray("data");
                JSONArray settingsArray = new JSONArray();
                //处理input参数，inputJsonArray存放着每一个子任务的input参数
                for(int m = 0;m<inputJsonArray.size();m++){
                    JSONObject oneFinal = new JSONObject();
                    //获取每一个子任务的输入参数
                    JSONArray oneTaskInputArray = inputJsonArray.getJSONArray(m);
                    JSONObject algorithmInput = new JSONObject();
                    //遍历每一个子任务的输入参数数组
                    for(int k=0;k<oneTaskInputArray.size();k++){
                        JSONObject oneAlgorithmInput = oneTaskInputArray.getJSONObject(k);
                        if(algorithmInput.containsKey(oneAlgorithmInput.getString("blockId"))){
                            algorithmInput.getJSONArray(oneAlgorithmInput.getString("blockId")).add(oneAlgorithmInput);
                        }else{
                            JSONArray temp = new JSONArray();
                            temp.add(oneAlgorithmInput);
                            algorithmInput.put(oneAlgorithmInput.getString("blockId"),temp);
                        }
                    }
                    oneFinal.put("inputs",algorithmInput);

                    JSONObject oneTaskOutputObject = new JSONObject();
                    oneTaskOutputObject.put("outputs",outputJsonArray.getJSONArray(m));
                    oneFinal.put("outputs",oneTaskOutputObject);
                    JSONObject algorithmParam = new JSONObject();
                    for(int h=0;h<blockIds.size();h++){
                        String blockId = blockIds.getString(h);
                        algorithmParam.put(blockId,paramJsonObject.getJSONArray(blockId).getJSONArray(m));
                    }
                    oneFinal.put("params",algorithmParam);
                    JSONArray dataArray = new JSONArray();
                    if(dataJsonArray.size()>0){
                        dataArray = dataJsonArray.getJSONArray(m);
                    }
                    oneFinal.put("data",dataArray);
                    settingsArray.add(oneFinal);
                }
                t.setJSON(taskJson);
                List<String> subTaskHashList = new ArrayList<>();
                for(int index=0;index<settingsArray.size();index++){
                    String subTaskHash = UUID.randomUUID().toString().substring(0,20);
                    subTaskHashList.add(subTaskHash);
                    RunningTaskBean runningTaskBean = new RunningTaskBean(task.getTask_id() + "",
                            subTaskHash, task.getJson(), task.getName());
                    runningTaskBean.setBatchTaskHash(batchTaskHash);
                    TaskThread taskA = new TaskThread(runningTaskBean);

                    taskA.runningTaskBean.runnableObjects = t.toRunnerableObjectMap(taskA,index+1,
                            settingsArray.getJSONObject(index).getJSONArray("data"),
                            settingsArray.getJSONObject(index).getJSONObject("inputs"),
                            settingsArray.getJSONObject(index).getJSONObject("outputs"),
                            settingsArray.getJSONObject(index).getJSONObject("params"));
                    orders=returnOrderStr( t,orders);
//                    orders =returnOrderStr( t,orders);
//                    try {
//                        addResult = addResult && historyDao.addHistoryByTask(task, subTaskHash,orders.toString(),taskHash);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
                    if(addResult)
                    {
                        taskThreadList.add(taskA);
                    }
                }
                addHistoryTask(task,subTaskHashList,batchTaskHash,historyDao);
                return taskThreadList;
            }else{
                return null;
            }
        }else{
            return null;
        }
    }

    public JSONObject startModel(String modelId, String taskHash, String priority,
                                 String parallelStrategy, List<String>
                                         modelXmlDirList, String userId){
        return this.startModel(modelId, taskHash, priority, parallelStrategy, modelXmlDirList, userId, null);
    }

    public JSONObject startModel(String modelId, String batchTaskHash, String priority,
                                 String parallelStrategy, List<String>
                                         modelXmlDirList, String userId,String json){
        Date date = new Date();
        JSONArray orders = new JSONArray();
        HistoryTaskDao historyDao = new HistoryTaskDao();
        ModelDao modelDao = new ModelDao();
        List<Object> list = modelDao.getModelByModelId(modelId);
        JSONObject result = new JSONObject();
        JSONArray subTaskHashArray = new JSONArray();
        if (list.size() == 0) {
            result.put("message", "数据库无此任务");
            result.put("result", false);
            return result;
        } else {
            ExternalInterfaceParseUtil externalInterfaceParseUtil = new ExternalInterfaceParseUtil();
            int modelIdInt = Integer.parseInt(modelId);
            Task task = externalInterfaceParseUtil.createTaskByModelId(userId, modelIdInt);
            //2018-8-22接口创建的task没有优先级和并行策略，这里进行添加
            JSONObject taskJson = JSONObject.parseObject(task.getJson());
            JSONArray other = new JSONArray();
            JSONObject oneOther = new JSONObject();
            oneOther.put("Priority",priority);
            oneOther.put("ParallelStrategy",parallelStrategy);
            if(json!=null && json.length()>2)
                oneOther.put("json", json);
            other.add(oneOther);
            taskJson.put("other",other);

            //  接口里没有input output等参数
      /*      JSONArray temp = new JSONArray();
            taskJson.put("inputs",temp);
            taskJson.put("outputs",temp);
            taskJson.put("data",temp);*/

            task.setJson(taskJson.toString());
            task.setUserId(userId);
            ParseTaskJson t = new ParseTaskJson();
            Set<String> algorithmIds = t.parseAlgorithmIds(task.getJson());
            Map<String,List<String>> algorithmIdAndFtpUri = new HashMap<>();
            for(String one:algorithmIds)
            {
                //      algorithmIdAndFtpUri.put(one,ftpuploadUtil.uploadAlgorithmFileByAlgorithmId(one));
                JSONObject versionInfo = JSONObject.parseObject(algorithmDao.getVersionInfoById(one).toString());
                Log4jInit.logger.info("one:algorithmIds  "+one);

                String tmp = versionInfo.get("ftp_uri")==null?(String) versionInfo.get("ftp_uri"):versionInfo.get("ftp_uri").toString();
                JSONArray ftpUri;

                if(tmp==null || tmp.trim().equals("") || tmp.trim().equals("[]")){
                    ftpUri=new JSONArray();
                    Log4jInit.logger.info("tmp null::"+tmp);
                }else{
                    ftpUri = versionInfo.getJSONArray("ftp_uri");
                    Log4jInit.logger.info("tmp::"+tmp);
                }

                //JSONArray ftpUri = (JSONArray) versionInfo.get("ftp_uri");

                String ftpVersion = (String) versionInfo.get("ftp_version");
                String version = (String) versionInfo.get("version");

                // 2019.3.26 如果ftp版本与算法版本一致，无需上传算法
                if((ftpUri.size()!=0)&&(ftpVersion.equals(version))){
                    //JSONArray jsonArray = JSONArray.fromObject(ftpUri); //把String转换为json
                    Log4jInit.logger.info("jsonArray JSONArray::"+JSON.toJSONString(ftpUri));
                    algorithmIdAndFtpUri.put(one,JSONArray.parseArray(JSON.toJSONString(ftpUri), String.class));
                }else {
                    List<String> ftpUriList = ftpuploadUtil.uploadAlgorithmFileByAlgorithmId(one);
                    Log4jInit.logger.info("ftpUriList ::"+ftpUriList.get(0));
                    algorithmIdAndFtpUri.put(one,ftpUriList);
                    algorithmDao.updateVersionInfoById(one, JSON.toJSONString(ftpUriList), version);
                }
            }
            List<Object> results = new TaskDao().addTask(task);
            String taskId = null;
            if(results.size()>0){
                taskId = results.get(0)+"";
            }

            Log4jInit.logger.info("algorithmIdAndFtpUri size:::"+algorithmIdAndFtpUri.size());
            //从task bean中读取task json
            boolean addResult = true;
            t.setModleJSON(taskJson);
            Log4jInit.logger.info("algorithmIdAndFtpUri size:::"+algorithmIdAndFtpUri.size());
            List<String> subList1 = new ArrayList<>();
            for(int index=0;index<modelXmlDirList.size();index++){
                String subModelHash = UUID.randomUUID().toString().substring(0,20);
                subList1.add(subModelHash);
                TaskThread taskA = taskForm(task, taskId, batchTaskHash,subModelHash,algorithmIdAndFtpUri);
                taskA.runningTaskBean.runnableObjects = t.toRunnerableObjectMapModel(taskA, priority, parallelStrategy);
                taskA.runningTaskBean.setModelXmlDir(modelXmlDirList.get(index));
                orders=returnOrderStr( t,orders);
                retResultMsg( addResult, taskA, subModelHash, subTaskHashArray,result);
            }
            if(subList1.size()>0){
                addHistoryTask(task, subList1, batchTaskHash, historyDao);
            }

            Log4jInit.logger.info("algorithmIdAndFtpUri size:::"+algorithmIdAndFtpUri.size());
            //若接口未传入文件，直接启动exe
            List<String> subList2 = new ArrayList<>();
            if(modelXmlDirList.size()==0){
                String subModelHash = UUID.randomUUID().toString().substring(0,20);
                subList2.add(subModelHash);
                TaskThread taskA = taskForm(task, taskId, batchTaskHash,subModelHash,algorithmIdAndFtpUri);
                taskA.runningTaskBean.runnableObjects = t.toRunnerableObjectMapModel
                        (taskA, priority, parallelStrategy);
                taskA.runningTaskBean.setModelXmlDir("");
                orders=returnOrderStr( t,orders);
                retResultMsg( addResult, taskA, subModelHash, subTaskHashArray,result);
            }
            if(subList2.size()>0){
                addHistoryTask(task, subList2, batchTaskHash, historyDao);
            }
            Log4jInit.logger.info("algorithmIdAndFtpUri size:::"+algorithmIdAndFtpUri.size());
            historyDao.addBatchTask(task, batchTaskHash,orders.toString(),date);
            result.put("subTaskHash", subTaskHashArray);
            result.put("batchTaskHash", batchTaskHash);
            result.put("orders",orders.toString());
            Log4jInit.logger.info("algorithmIdAndFtpUri size:::"+algorithmIdAndFtpUri.size());
            return result;
        }
    }

    private void addHistoryTask(Task task,List<String> subTaskHashList,String batchTaskHash,HistoryTaskDao historyDao){

        try {
            /* addResult = addResult && historyDao.addHistoryByTask(task,
                     subModelHash,orders.toString(),taskHash);*/
            boolean result = historyDao.addSubTaskByBatch(task, subTaskHashList, batchTaskHash);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private TaskThread taskForm(Task task,String taskId,String taskHash,String subModelHash,Map<String,List<String>> algorithmIdAndFtpUri){


        RunningTaskBean runningTaskBean = new RunningTaskBean(taskId + "",
                subModelHash, task.getJson(), task.getName());
        runningTaskBean.setBatchTaskHash(taskHash);
        runningTaskBean.setAlgorithmIdAndFtpUri(algorithmIdAndFtpUri);
        TaskThread taskA = new TaskThread(runningTaskBean);

        return taskA;
    }

    private JSONArray returnOrderStr(ParseTaskJson t,JSONArray orders){
        if(orders == null){
            orders = new JSONArray();
        }
        if(orders.size()==0){
            ArrayList<UIAlgorithmDetail> orderedDetails = t.getOrderedDetails();
            for(UIAlgorithmDetail uia:orderedDetails){
                JSONObject one = new JSONObject();
                one.put("blockId",uia.getBlockId());
                one.put("algorithmName",algorithmDao.getAlgorithmNameById(uia.getAlgorithmId()));
                orders.add(one);
            }
        }
        return orders;
    }

    private JSONObject retResultMsg(boolean addResult,TaskThread taskA,String subModelHash,JSONArray subTaskHashArray,JSONObject result){

        if (addResult) {
            taskA.start();
            RunningTask.TASKMAP.setTask(taskA.runningTaskBean.getTaskHash(), taskA);
            subTaskHashArray.add(subModelHash);
            result.put("message", "开始任务成功");
            result.put("result", true);

        } else {
            result.put("message", "添加历史任务时失败");
            result.put("result", false);
        }

        return result;
    }



}
